/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "sys/time.h"
#include "compatibility/libc/time/clock_time.h"

/*******************************************************************************
 * Macro operate
 ******************************************************************************/
#define INT64T_MAX (9223372036854775807LL)
/* \brief 一天的秒数量 */
#define SPD         24 * 60 * 60

/*******************************************************************************
 * Static
 ******************************************************************************/
static int64_t __g_system_time_base = 0LL;

static const short __spm[13] =
{   0,
    (31),
    (31 + 28),
    (31 + 28 + 31),
    (31 + 28 + 31 + 30),
    (31 + 28 + 31 + 30 + 31),
    (31 + 28 + 31 + 30 + 31 + 30),
    (31 + 28 + 31 + 30 + 31 + 30 + 31),
    (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31),
    (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30),
    (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31),
    (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30),
    (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31),
};

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief 获取系统时间
 */
static int32_t __system_time_get(time_t *p_time){
    int32_t  rc = 0;
    uint64_t ts = Wed_tick_get() / 1000;

    if (p_time == NULL) {
        rc = -1;
    }
    /* 检查是否溢出 */
    else if ((ts > INT64T_MAX) ||    /* pre-check downcast precision loss */
        ((int64_t) ts > ((int64_t) INT64T_MAX - __g_system_time_base))) {
        rc = -1;
    } else {
        *p_time = (time_t) (__g_system_time_base + (int64_t) ts);
    }

    return (rc);
}

/**
 * \brief 每四年有一个闰年，但能被 100 整除的世纪年份除外，除非该年份也能被 400 整除
 *        return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
 */
static int __isleap(int year){
    return (!(year % 4) && ((year % 100) || !(year % 400)));
}

/**
 * \brief 获取系统时间
 */
time_t time(time_t *p_timer){
    time_t tv;

    if (__system_time_get(&tv) != 0) {
        tv = (time_t) -1;
    }

    if (p_timer) {
        *p_timer = tv;
    }

    return (tv);
}

/**
 * \brief 将分解时间（struct tm）转换为日历时间（time_t）
 *
 * @param t 分解时间
 *
 * @return 返回日历时间
 */
time_t mktime(struct tm * const t){
    register time_t day;
    register time_t i;
    register time_t years = t->tm_year - 70;

    if (t->tm_sec > 60) {
        t->tm_min += t->tm_sec / 60;
        t->tm_sec %= 60;
    }
    if (t->tm_min > 60) {
        t->tm_hour += t->tm_min / 60;
        t->tm_min %= 60;
    }
    if (t->tm_hour > 24) {
        t->tm_mday += t->tm_hour / 24;
        t->tm_hour %= 24;
    }
    if (t->tm_mon > 12) {
        t->tm_year += t->tm_mon / 12;
        t->tm_mon %= 12;
    }
    while (t->tm_mday > __spm[1 + t->tm_mon]) {
        if (t->tm_mon == 1 && __isleap(t->tm_year + 1900)) {
            --t->tm_mday;
        }
        t->tm_mday -= __spm[t->tm_mon];
        ++t->tm_mon;
        if (t->tm_mon > 11) {
            t->tm_mon = 0;
            ++t->tm_year;
        }
    }

    if (t->tm_year < 70) {
        return (time_t) - 1;
    }

    /* Days since 1970 is 365 * number of years + number of leap years since 1970 */
    day = years * 365 + (years + 1) / 4;

    /* After 2100 we have to substract 3 leap years for every 400 years
     This is not intuitive. Most mktime implementations do not support
     dates after 2059, anyway, so we might leave this out for it's
     bloat. */
    if (years >= 131) {
        years -= 131;
        years /= 100;
        day -= (years >> 2) * 3 + 1;
        if ((years &= 3) == 3) {
            years--;
        }
        day -= years;
    }

    day += t->tm_yday = __spm[t->tm_mon] + t->tm_mday - 1 +
                        (__isleap(t->tm_year + 1900) & (t->tm_mon > 1));

    /* day is now the number of days since 'Jan 1 1970' */
    i = 7;
    t->tm_wday = (day + 4) % i; /* Sunday=0, Monday=1, ..., Saturday=6 */

    i = 24;
    day *= i;
    i = 60;
    return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec;
}

/**
 * \brief 获取当前日期时间
 *
 * @param p_tp     存储时间的结构体
 * @param p_ignore
 *
 * @return 返回秒数
 */
int gettimeofday(struct timeval *p_tp, void *p_ignore){
    time_t          time = 0;
    struct timespec tp   = {0};

    clock_gettime(CLOCK_REALTIME, &tp);

    time          = tp.tv_sec;
    p_tp->tv_sec  = time;
    p_tp->tv_usec = 0;

    return time;
}

/**
 * \brief 将日历时间（time_t）转换为分解时间（struct tm）
 *
 * @param p_timep 日历时间
 * @param p_r     存储分解时间的结构体
 *
 * @return 返回分解的时间结构体
 */
struct tm *gmtime_r(const time_t *p_timep, struct tm *p_r){
    time_t          i;
    register time_t work = *p_timep % (SPD);

    p_r->tm_sec = work % 60;
    work /= 60;
    p_r->tm_min = work % 60;
    p_r->tm_hour = work / 60;
    work = *p_timep / (SPD);
    p_r->tm_wday = (4 + work) % 7;

    for (i = 1970;; ++i) {
        register time_t k = __isleap(i) ? 366 : 365;
        if (work >= k) {
            work -= k;
        } else {
            break;
        }
    }
    p_r->tm_year = i - 1900;
    p_r->tm_yday = work;

    p_r->tm_mday = 1;
    if (__isleap(i) && (work > 58)) {
        if (work == 59) {
            p_r->tm_mday = 2; /* 29.2. */
        }
        work -= 1;
    }

    for (i = 11; i && (__spm[i] > work); --i)
        ;
    p_r->tm_mon = i;
    p_r->tm_mday += work - __spm[i];
    return p_r;
}

/**
 * \brief 计算两个 time_t 类型的时间点之间的时间差（以秒为单位）
 *
 * @param time1 结束时间（较晚的时间点）
 * @param time0 起始时间（较早的时间点）
 *
 * @return 返回一个 double 类型的值，表示两个时间之间的秒数差
 */
double difftime(time_t time1, time_t time0){
    return (double)(time1 - time0);
}
